package com.sff.webservice.data {
	
	import flash.events.EventDispatcher;
	
	public class WSOperations extends EventDispatcher {
		
		private var arrMethod	:Array;
		private var arrComplex	:Array;
		private var arrResponse	:Array;
		private var arrBinding	:Array;		
		private var strTargetNS	:String;		
		private var _porttype	:Boolean = false;
		
		public function WSOperations() {
			arrMethod = new Array();
			arrResponse = new Array();
			arrComplex = new Array();
			arrBinding = new Array();
		}
		
		public function parse(xml:XML):void {	
			var defaultNS:Namespace = xml.namespace();
			
			var xmlTypes:XML = xml.defaultNS::types[0];
			var xmlPortTypes:XML = xml.defaultNS::portType[0];
			var xmlBinding:XML = xml.defaultNS::binding[0];			
			var xmlMessage:XMLList = xml.defaultNS::message;
			
			var soapNS:Namespace = xmlTypes.children()[0].namespace();
			var xmlSoap:XML = xmlTypes.soapNS::schema[0];
			
			try {
				strTargetNS = xml.@targetNamespace.toString();
			}
			catch (err:Error) { }
			
			if(xmlTypes.children().length() > 0 && xmlSoap.soapNS::element.length() > 0) {
				// METHODS / COMPLEX TYPES
				extractMethods(xmlSoap, soapNS);
			}
			
			else {
				// PORTMETHODS				
				extractPortMethods(xmlPortTypes[0], xmlPortTypes.children()[0].namespace(), xmlPortTypes.@name, xmlMessage);
			}
			
			extractComplexType(xmlSoap, soapNS);
			extractSimpleType(xmlSoap, soapNS);
			
			// BINDINGS
			extractBindings(xmlBinding[0], xmlBinding.namespace());
			
		}
		
		private function extractBindings(xml:XML, ns:Namespace):void {	
			
			var soapNS:Namespace = xml.namespace("soap");
			
			if(!extractBindingWithNameSpace(xml, ns, soapNS)) {
				soapNS = xml.namespace("wsdlsoap");				
				extractBindingWithNameSpace(xml, ns, soapNS);
			}
		}
		
		private function extractBindingWithNameSpace(xml:XML, ns:Namespace, bindingNS:Namespace):Boolean {
			var bFailed:Boolean = false;
			
			var wsBinding:WSBinding;
			var xmlInput:XML;
			var xmlOutput:XML;
			
			
			for each(var xmlNode:XML in xml.ns::operation) {
				wsBinding = new WSBinding(xmlNode.@name.toString());
						
				try {
					xmlInput = xmlNode.ns::input[0];
					
					wsBinding.addInputNamespace(xmlInput.bindingNS::body[0].attribute("namespace"));
					wsBinding.addInputUse(xmlInput.bindingNS::body[0].attribute("use"));
					
					xmlOutput = xmlNode.ns::output[0];
					
					wsBinding.addOutputNamespace(xmlOutput.bindingNS::body[0].attribute("namespace"));
					wsBinding.addOutputUse(xmlOutput.bindingNS::body[0].attribute("use"));
					
					arrBinding.push(wsBinding);
					
				} catch(e:Error) {
					bFailed = true;
				}
			}
			
			return !bFailed;
		}
		
		private function extractPortMethods(xml:XML, ns:Namespace, methodName:String, xmlList:XMLList):void {
			
			_porttype = true;
			
			var wsMethod:WSMethod;
			var xmlMessage:XML;
			
			for each(var xmlNode:XML in xml.ns::operation) {
				try {
					//METHODS
					wsMethod = new WSMethod(xmlNode.@name.toString());
					xmlMessage = xmlList.(attribute("name") == (methodName + "_" + wsMethod.name))[0];
					
					if(xmlMessage == null) {
						xmlMessage = xmlList.(attribute("name") == (wsMethod.name))[0];
					}

					if(xmlMessage != null) {
						for each(var xmlMethod:XML in xmlMessage.ns::part) {			
							wsMethod.addArgument(new WSArgument(xmlMethod.@name.toString(), xmlMethod.@type.toString()));
						}	
					}
					arrMethod.push(wsMethod);					
					
					//RESPONSES
					wsMethod = new WSMethod(xmlNode.ns::output.@message.split(":")[1].split("_")[1]);
					xmlMessage = xmlList.(attribute("name") == (methodName + "_" + wsMethod.name))[0];
					
					if(xmlMessage == null) {
						xmlMessage = xmlList.(attribute("name") == (wsMethod.name))[0];
					}
					
					if(xmlMessage != null) {
						for each(var xmlResponse:XML in xmlMessage.ns::part) {			
							wsMethod.addArgument(new WSArgument(xmlResponse.@name.toString(), xmlResponse.@type.toString()));
						}	
					}					
					arrResponse.push(wsMethod);					
				}
				catch(err:Error) {}				
			}		
		}
		
		private function extractMethods(xml:XML, ns:Namespace):void {
			
			var xmlComplex:XML;
			var xmlSequence:XML;
			var xmlList:XMLList;
			var wsMethod:WSMethod;
			
			for each(var xmlNode:XML in xml.ns::element) {				
				try {
					xmlComplex = xmlNode.ns::complexType[0];
					
					// ARGUMENTEN XML
					xmlSequence = xmlComplex.ns::sequence.length() > 0 ? xmlComplex.ns::sequence[0] : null;
					xmlList = xmlSequence == null ? new XMLList() : xmlSequence.ns::element;
					
					// METHODS
					if(xmlNode.@name.indexOf("Response") <= 0) {
						wsMethod = new WSMethod(xmlNode.@name.toString());
						
						for each(var xmlMethod:XML in xmlList) {			
							wsMethod.addArgument(new WSArgument(xmlMethod.@name.toString(), xmlMethod.@type.toString()));
						}
						arrMethod.push(wsMethod);
					}
					
					else {
						// RESPONSES
						wsMethod = new WSMethod(xmlNode.@name.toString());
						
						for each(var xmlResponse:XML in xmlList) {			
							wsMethod.addArgument(new WSArgument(xmlResponse.@name.toString(), xmlResponse.@type.toString()));
						}
						
						arrResponse.push(wsMethod);						
					}
				} catch(err:Error) {}				
			}			
		}
		
		private function extractSimpleType(xml:XML, ns:Namespace):void {
			
			var wsMethod:WSMethod;
			for each(var xmlNode:XML in xml.ns::simpleType) {
				try {
					wsMethod = new WSMethod(xmlNode.@name.toString());
					arrComplex.push(wsMethod);
				} catch(e:Error) {}				
			}			
		}		
		
		private function extractComplexType(xml:XML, ns:Namespace):void {
			
			var xmlSequence:XML;
			var xmlList:XMLList;
			var wsMethod:WSMethod;
			
			for each(var xmlNode:XML in xml.ns::complexType) {
				
				try {
					wsMethod = new WSMethod(xmlNode.@name.toString());					
					xmlSequence = xmlNode.ns::sequence[0];					
					xmlList = xmlSequence == null ? new XMLList() : xmlSequence.ns::element;
					
					for each(var xmlArgument:XML in xmlList) {	
						wsMethod.addArgument(new WSArgument(xmlArgument.@name.toString(), xmlArgument.@type.toString()));
					}	
					
					arrComplex.push(wsMethod);
				} catch(err:Error) {}				
			}			
		}		
		
		/**
		* Get Method object
		*/		
		public function getMethodObject(methodName:String):WSMethod {
			
			for(var i:int = 0; i < arrMethod.length; i++) {
				
				if(arrMethod[i].name == methodName){ 
					return arrMethod[i]; 
				}
			}
			
			return null;
		}

		/**
		* Get WebService Argument from a MethodObject
		*/
		public function getMethodObjectArgument(arrArgument:Array, methodName:String):WSArgument {
			
			for(var i:int = 0; i < arrArgument.length; i++) {
				
				if(arrArgument[i].name == methodName) {
					return arrArgument[i]; 
				}
			}
			
			return null;
		}		
		
		/**
		* Get Response object
		*/		
		public function getResponseObject(resposeName:String):WSMethod {
			
			for(var i:int = 0; i < arrResponse.length; i++) {
				
				if(arrResponse[i].name == resposeName){ 
					return arrResponse[i]; break; 
				}
			}
			
			return null;
		}
		
		/**
		* Get Complex object
		*/
		public function getComplexObject(complexName:String):WSMethod {
			
			for(var i:int = 0; i < arrComplex.length; i++) {
				
				if(arrComplex[i].name == complexName){ 
					return arrComplex[i];  
				}
			}
			
			return null;
		}
		
		/**
		* Get Binding object
		*/
		public function getBindingObject(bindingName:String):WSBinding {
			
			for(var i:int = 0; i < arrBinding.length; i++) {
				
				if(arrBinding[i].name == bindingName){ 
					return arrBinding[i]; 
				}
			}
			
			return null;
		}
		
		/**
		* Get WSArgument from a ComplexObject
		*/
		public function getComplexObjectArgument(arrArgument:Array, argumentName:String):WSArgument {
			
			for(var i:int = 0; i < arrArgument.length; i++) {
				
				if(arrArgument[i].name == argumentName){ 
					return arrArgument[i]; 
				}
			}			
			return null;
		}		
				
		/**
		 * check operation exist or not
		 */
		public function methodExists(methodName:String):Boolean {			
			for(var i:int = 0; i < arrMethod.length; i++) {
				if (arrMethod[i].name == methodName) { 
					return true;
				}
			}			
			return false;			
		}
		
		public function get targetNameSpace():String {
			return strTargetNS;
		}
		
		public function isPortType():Boolean {
			return _porttype;
		}		
	}
}
